//
//	MTRespondingView.m
//  MultiTouch2OSC
//
//  Created by Michael Gubik in October 2009.
//	Uses some Multi-Touch code written by Gernot Poetsch
//		on 19.09.09 at Music Hack Day Berlin
//
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//


#import "MTRespondingView.h"
#import <VVOSC/VVOSC.h>

@interface MTRespondingView (Private)
- (void)updateTouchArrayWithTouches:(NSSet *)touches;
@end


@implementation MTRespondingView

  @synthesize touchArray;

#pragma mark Lifecycle

- (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
		[self setAcceptsTouchEvents:YES];
		[self setWantsRestingTouches:YES];

		touchArray = [[NSArray alloc] init];
		numberOfVoidTouchesAtArrayEnd = 0;
    }
    return self;
}

- (void)awakeFromNib {	
		
}

- (void)dealloc {
//	if ( appController )
//		[self removeObserver:appController forKeyPath:@"touchArray"];
	[touchArray release];
	[touchSet release];
	[super dealloc];
}

#pragma mark Accessors

- (void)setTouchSet:(NSSet *)newTouchSet {
	[newTouchSet retain]; [touchSet release]; touchSet = newTouchSet;
	
	[self updateTouchArrayWithTouches:touchSet];
}


#pragma mark Touch Events

- (void)touchesBeganWithEvent:(NSEvent *)event {
	//NSLog(@"Touches Began");
	[self setTouchSet:[event touchesMatchingPhase:NSTouchPhaseTouching inView:self]];
}

- (void)touchesMovedWithEvent:(NSEvent *)event {
	//NSLog(@"Touches Moved");
	[self setTouchSet:[event touchesMatchingPhase:NSTouchPhaseTouching inView:self]];
}

- (void)touchesEndedWithEvent:(NSEvent *)event {
	//NSLog(@"Touches Ended");
	[self setTouchSet:[event touchesMatchingPhase:NSTouchPhaseTouching inView:self]];
}

- (void)touchesCancelledWithEvent:(NSEvent *)event {
	//NSLog(@"Touches Cancelled");
	[self setTouchSet:[event touchesMatchingPhase:NSTouchPhaseTouching inView:self]];
}

#pragma mark Responder

- (BOOL)acceptsFirstResponder {
	return YES;
}


#pragma mark -
#pragma mark Private

- (void)updateTouchArrayWithTouches:(NSSet *)touches
{
	NSMutableArray *newTouchArray = [[NSMutableArray alloc] initWithCapacity:touchArray.count];
	
	//  persisting touches are getting updated and withdrawn touches null'd
	for (NSTouch *oldTouch in touchArray) {
		if (![oldTouch isEqual:[NSNull null]]) {
			id newTouch = [NSNull null];
			for (NSTouch *newTouchCandidate in touches) {
				if ([oldTouch.identity isEqual:newTouchCandidate.identity]) {
					newTouch = newTouchCandidate;
					break;
				}
			}
			[newTouchArray addObject:newTouch];
		} else {
			[newTouchArray addObject:oldTouch];
		}
	}
	
	// add new touches
	for (NSTouch *newTouch in touches) {
		BOOL newTouchIsThere = NO;
		for (NSTouch *oldTouchCandidate in touchArray) {
			if (![oldTouchCandidate isEqual:[NSNull null]] && [oldTouchCandidate.identity isEqual:newTouch.identity]) {
				newTouchIsThere = YES;
				break;
			}
		}
		
		if (!newTouchIsThere) {
			NSInteger indexForReplacement;
			BOOL foundEmptyTouchInArray = NO;
			for (indexForReplacement=0; indexForReplacement<newTouchArray.count; indexForReplacement++) {
				if ([[newTouchArray objectAtIndex:indexForReplacement] isEqual:[NSNull null]]) {
					[newTouchArray replaceObjectAtIndex:indexForReplacement withObject:newTouch];
					foundEmptyTouchInArray = YES;
					break;
				}
			}
			if (!foundEmptyTouchInArray) {
				[newTouchArray addObject:newTouch];
			}
		}
	}
	
	// strip void touches from array end
	// only after they've already been null for one cycle (makes it easier for the client to e.g. mute a synth)
	NSInteger nextRunNumberOfVoidTouchesAtArrayEnd = 0;

	for ( NSInteger i=newTouchArray.count-1; i>=0; i-- ){
		if ( [[newTouchArray objectAtIndex:i] isEqual:[NSNull null]] ) {
			if ( numberOfVoidTouchesAtArrayEnd > 0 ){
				[newTouchArray removeLastObject];
				numberOfVoidTouchesAtArrayEnd--; 
			} else {
				nextRunNumberOfVoidTouchesAtArrayEnd++;
			}
		} else {
			break;
		}
	}

	numberOfVoidTouchesAtArrayEnd = nextRunNumberOfVoidTouchesAtArrayEnd;
	
	[self willChangeValueForKey:@"touchArray"];
	[touchArray release];
	touchArray = newTouchArray;
	[self didChangeValueForKey:@"touchArray"];
}


- (void)keyDown:(NSEvent *)theEvent {
	[appController keyDown:theEvent];
}

 

- (void)drawRect:(NSRect)dirtyRect {
}

@end
